
/*
    Software License

    Copyright (C) 2021-05-24  Xoronos

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

/*
    Liabilities

    The software is provided "AS IS" without any warranty of any kind, either expressed,
    implied, or statutory, including, but not limited to, any warranty that the software
    will conform to specifications, any implied warranties of merchantability, fitness
    for a particular purpose, and freedom from infringement, and any warranty that the
    documentation will conform to the software, or any warranty that the software will
    be error free.

    In no event shall Xoronos be liable for any damages, including, but not limited to,
    direct, indirect, special or consequential damages, arising out of, resulting from,
    or in any way connected with this software, whether or not based upon warranty,
    contract, tort, or otherwise, whether or not injury was sustained by persons or
    property or otherwise, and whether or not loss was sustained from, or arose out of
    the results of, or use of, the software or services provided hereunder.

    To request the provided software under a different license you can contact us at
    support@xoronos.com
*/

#include "xrn_core.h"
#include "xrn_core_backend.h"

int xrn_matrix_check_wrapper( FILE * xrn_matrix_fpr, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_matrix_t *xm;
    int ret;
    int final_ret;

    if ( xrn_matrix_fpr == NULL ) {
        XPRINT_ERR( 1997, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // load matrix        

    xm = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xm == NULL ) {
        XPRINT_ERR( 1998, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix( xrn_matrix_fpr, xm, settings );
    if ( XSUCCESS != ret ) {
        XRN_FREE( xm );
        XPRINT_ERR( 1999, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_matrix_check( xm );

    XRN_FREE( xm );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 716, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_matrix_decompress_wrapper( FILE * xrn_matrix_compressed_fpr, FILE * xrn_matrix_decompressed_fpw,
                                   xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_matrix_t *xm;
    xrn_matrix_compressed_t *xmc;
    int final_ret, ret;
    xrn_log_t xlog2;

    if ( ( xrn_matrix_compressed_fpr == NULL ) || ( xrn_matrix_decompressed_fpw == NULL ) ) {
        XPRINT_ERR( 2000, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.i_settings ) ) {
        XPRINT_ERR( 662, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    // load matrix 

    xm = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xm == NULL ) {
        XPRINT_ERR( 2001, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // load matrix compressed 

    xmc = ( xrn_matrix_compressed_t * ) malloc( sizeof( xrn_matrix_compressed_t ) );

    if ( xmc == NULL ) {
        XRN_FREE( xm );
        XPRINT_ERR( 2002, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix_compressed( xrn_matrix_compressed_fpr, xmc, settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xm );
        XRN_FREE( xmc );
        XPRINT_ERR( 2003, XERR_GENERAL_MSG );
        return ret;
    }

    // check if the matrix compressed is valid
    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_compressed_check( xmc );
    xlog = xlog2;

    if ( ret == XERR_NOT_GENESIS ) {
        XRN_FREE( xm );
        XRN_FREE( xmc );
        XPRINT_ERR( 2004, XERR_NOT_GENESIS_MSG );
        return XERR_NOT_GENESIS;
    }

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xm );
        XRN_FREE( xmc );
        XPRINT_ERR( 2005, XERR_GENERAL_MSG );
        return ret;
    }

    // decompress matrix

    xrn_matrix_decompress( xmc, xm );

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_check( xm );
    xlog = xlog2;

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xm );
        XRN_FREE( xmc );
        XPRINT_ERR( 2006, XERR_GENERAL_MSG );
        return ret;
    }

    // dump matrix

    ret = xrn_dump_matrix( xm, xrn_matrix_decompressed_fpw, settings );

    XRN_FREE( xm );
    XRN_FREE( xmc );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2007, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

void xrn_matrix_decompress( xrn_matrix_compressed_t * xmc, xrn_matrix_t * xmd
 )
{
    XPRINT_DEB(  );

    xgenesis_base_2_xrn_matrix( &xmc->xgenesis_base, &xmc->change_of_base, &xmc->change_of_sign, xmd );
    return;
}

int xrn_matrix_compressed_check_wrapper( FILE * xrn_matrix_compressed_fpr, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_matrix_compressed_t *xmc;
    int final_ret, ret;

    if ( xrn_matrix_compressed_fpr == NULL ) {
        XPRINT_ERR( 2008, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.i_settings ) ) {
        XPRINT_ERR( 663, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    // load matrix compressed 

    xmc = ( xrn_matrix_compressed_t * ) malloc( sizeof( xrn_matrix_compressed_t ) );

    if ( xmc == NULL ) {
        XPRINT_ERR( 2009, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix_compressed( xrn_matrix_compressed_fpr, xmc, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xmc );
        XPRINT_ERR( 2010, XERR_GENERAL_MSG );
        return ret;
    }

    // check if the matrix compressed is valid

    ret = xrn_matrix_compressed_check( xmc );
    XRN_FREE( xmc );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_NOT( 1 );
        return ret;
    }

    XPRINT_NOT( 0 );
    return XSUCCESS;
}

int xrn_matrix_compressed_check( xrn_matrix_compressed_t * xmc
 )
{
    XPRINT_DEB(  );

    int final_ret, ret;

    final_ret = XSUCCESS;

    ret = xrn_check_sparsity( xmc->change_of_sign );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 713, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_check_sparsity( xmc->change_of_base );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 714, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_check_genesis_base( &xmc->xgenesis_base );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 735, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;

}

int xrn_matrix_compressed_permute_wrapper( FILE * xrn_matrix_compressed_fpr,
                                           FILE * xrn_matrix_compressed_fpw,
                                           xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_matrix_compressed_t *xmc;
    int final_ret, ret;
    xrn_log_t xlog2;

    if ( ( xrn_matrix_compressed_fpr == NULL ) || ( xrn_matrix_compressed_fpw == NULL ) ) {
        XPRINT_ERR( 2011, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.i_settings ) ) {
        XPRINT_ERR( 664, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    // load matrix compressed 

    xmc = ( xrn_matrix_compressed_t * ) malloc( sizeof( xrn_matrix_compressed_t ) );

    if ( xmc == NULL ) {
        XPRINT_ERR( 2012, XERR_NULL_MSG );
        return XERR_NULL;
    }

    ret = xrn_load_matrix_compressed( xrn_matrix_compressed_fpr, xmc, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xmc );
        XPRINT_ERR( 2013, XERR_GENERAL_MSG );
        return ret;
    }

    // check if the matrix compressed is valid

    xlog2 = xlog;
    xlog.not_en = 0;
    ret = xrn_matrix_compressed_check( xmc );
    xlog = xlog2;

    if ( ret == XERR_NOT_GENESIS ) {
        XRN_FREE( xmc );
        XPRINT_ERR( 2014, XERR_NOT_GENESIS_MSG );
        return XERR_NOT_GENESIS;
    }

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xmc );
        XPRINT_ERR( 2015, XERR_GENERAL_MSG );
        return ret;
    }

    xrn_matrix_compressed_permute( xmc );

    ret = xrn_dump_matrix_compressed( xmc, xrn_matrix_compressed_fpw, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XRN_FREE( xmc );
        XPRINT_ERR( 2016, XERR_GENERAL_MSG );
        return ret;
    }

    XRN_FREE( xmc );

    return final_ret;

}

int xrn_matrix_compressed_permute( xrn_matrix_compressed_t * xmc
 )
{
    XPRINT_DEB(  );

    int error, ret;
    xrn_matrix_t *xm;
    xrn_log_t xlog2;

    if ( xmc == NULL ) {
        XPRINT_ERR( 2017, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // load matrix 

    xm = ( xrn_matrix_t * ) malloc( sizeof( xrn_matrix_t ) );

    if ( xm == NULL ) {
        XPRINT_ERR( 2018, XERR_NULL_MSG );
        return XERR_NULL;
    }

    xlog2 = xlog;
    xlog.err_en = 0;
    xlog.war_en = 0;
    xlog.not_en = 0;

    error = 1;
    while ( error == 1 ) {

        error = 0;
        xrn_initialize_true_rnd_num( "", &xmc->change_of_base );
        xrn_initialize_true_rnd_num( "", &xmc->change_of_sign );

        // decompress matrix

        xrn_matrix_decompress( xmc, xm );

        ret = xrn_matrix_check( xm );

        if ( ret != XSUCCESS ) {
            error = 1;
        }

    }

    xlog = xlog2;

    XRN_FREE( xm );

    return XSUCCESS;
}

int xrn_check_genesis_base( xgenesis_base_t * obase
 )
{
    XPRINT_DEB(  );

    XBIT_TYPE error;
    xrn_base_t xbo;
    xrn_base_t xb;
    xmat_t xmat;
    xnum_t sign;
    int i;

    if ( obase == NULL ) {
        XPRINT_ERR( 2019, XERR_NULL_MSG );
        return XERR_NULL;
    }

    xgenesis_base_v2m( obase, &xmat );

    // initialize the sign vector
    xrn_initialize_num( &sign );

    // initialize xoron base
    xb.base_matrix = xmat;
    xb.sign_vector = sign;

    // assume that there is no error
    error = 0;

    // original origin base
    xbo = xb;

    // test xrn_doubling for function
    for ( i = 0; ( i < ( sizeof( xnum_t ) * 8 ) ) && ( !error ); i++ ) {

        xrn_doubling( &xb, &xb );

        if ( i == ( sizeof( xnum_t ) * 8 ) - 1 ) {
            // check if the Nth result is equal to the beginning
            error = xrn_compare_bases( &xb, &xbo );

        } else {
            // check if the non Nth result is different to the beginning
            error = !xrn_compare_bases( &xb, &xbo );

        }

    }

    if ( error ) {
        return XERR_NOT_GENESIS;
    }

    return XSUCCESS;

}

int xrn_matrix_check( xrn_matrix_t * xml
 )
{
    XPRINT_DEB(  );

    XBIT_TYPE error;
    int i, j, k, indexi, indexj, error_running, error_ratio, error_plain_detected, error_permuted_detected,
        error_nlinearity_detected;
    int ret, final_ret;
    int num_0, num_1, max_cons_0, max_cons_1, total_n0, total_n1;
    int mask, byte;
    xnum_t point_0, point_1, point_2, point_22, dc, dci, tmp;
    uint8_t permutations[XNBITS] = XRN_PERMUTATIONS;
    traverse_opt_t trav_tmp;

    if ( xml == NULL ) {
        XPRINT_ERR( 2020, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    num_0 = 0;
    num_1 = 0;
    max_cons_0 = 0;
    max_cons_1 = 0;
    total_n0 = 0;
    total_n1 = 0;

    ret = xrn_check_sparsity( xml->xrn_dead_code );
    if ( ret != XSUCCESS ) {
        XPRINT_ERR( 732, XERR_GENERAL_MSG );
        return ret;
    }

    for ( i = 0; i < XNBITS; i++ ) {

        ret = xrn_check_sparsity( xml->xvector[i].entry_point );
        if ( ret != XSUCCESS ) {
            XPRINT_ERR( 733, XERR_GENERAL_MSG );
            return ret;
        }

        for ( j = 0; j < XNBITS; j++ ) {

            mask = 1;
            byte = ( int ) ( ( ( uint8_t * ) & xml->xvector[i].xbase.base_matrix.xmat )[j] );

            for ( k = 0; k < 8; k++ ) {
                if ( ( byte & mask ) == mask ) {

                    num_1++;

                    if ( max_cons_0 < num_0 ) {
                        max_cons_0 = num_0;
                    }

                    total_n0 = total_n0 + num_0;
                    num_0 = 0;

                } else {

                    num_0++;

                    if ( max_cons_1 < num_1 ) {
                        max_cons_1 = num_1;
                    }

                    total_n1 = total_n1 + num_1;
                    num_1 = 0;

                }

                mask = mask << 1;

            }

        }

    }

    error_running = 0;
    error_ratio = 0;

    if ( ( max_cons_0 > 50 ) || ( max_cons_1 > 50 ) ) {
        error_running = 1;
    }

    if ( total_n0 > total_n1 ) {
        if ( total_n0 / total_n1 > 1.001 ) {
            error_ratio = 1;
        }

    } else {
        if ( total_n1 / total_n0 > 1.001 ) {
            error_ratio = 1;
        }

    }

    // check plain xrn_doubling property

    xrn_initialize_rnd_num( &point_0 );
    error_plain_detected = 0;
    error_permuted_detected = 0;
    error_nlinearity_detected = 0;

    error = 0;
    for ( i = 0; ( i < ( sizeof( xnum_t ) * 8 ) ) && ( !error ); i++ ) {

        j = ( i + 1 ) % ( ( int ) sizeof( xnum_t ) * 8 );

        // check internal xoron vector
        xrn_vector_traverse( &xml->xvector[i], &xml->xrn_dead_code, &point_0, &point_1, &trav_tmp );
        xrn_vector_traverse( &xml->xvector[i], &xml->xrn_dead_code, &point_1, &point_2, &trav_tmp );
        xrn_vector_traverse( &xml->xvector[j], &xml->xrn_dead_code, &point_0, &point_22, &trav_tmp );

        XNUM_CMP( point_2, point_22, error );

        if ( error ) {

            error_plain_detected = 1;

        }

        XNUM_CMP( point_1, point_22, error );

        if ( !error ) {

            error_plain_detected = 1;

        }

        error = 0;

    }

    indexj = 0;
    indexi = 0;

    // check permuted xrn_doubling property

    error = 0;
    for ( i = 0; ( i < XNBITS ) && ( !error ); i++ ) {

        j = ( i + 1 ) % ( ( int ) XNBITS );

        for ( k = 0; k < XNBITS; k++ ) {

            if ( permutations[k] == i ) {
                indexi = k;
            }

            if ( permutations[k] == j ) {
                indexj = k;
            }

        }

        // check internal xoron vector
        xrn_vector_traverse( &xml->xvector[indexi], &xml->xrn_dead_code, &point_0, &point_1, &trav_tmp );
        xrn_vector_traverse( &xml->xvector[indexi], &xml->xrn_dead_code, &point_1, &point_2, &trav_tmp );
        xrn_vector_traverse( &xml->xvector[indexj], &xml->xrn_dead_code, &point_0, &point_22, &trav_tmp );

        XNUM_CMP( point_2, point_22, error );

        if ( error ) {

            error_permuted_detected = 1;

        }

        XNUM_CMP( point_1, point_22, error );

        if ( !error ) {

            error_permuted_detected = 1;

        }

        error = 0;

    }

    // check non linearity
    // entry point -> dead code -> dead code inverted

    error = 0;
    for ( i = 0; ( i < ( sizeof( xnum_t ) * 8 ) ) && ( !error ); i++ ) {

        xrn_vector_traverse( &xml->xvector[i], &xml->xrn_dead_code, &xml->xvector[i].entry_point, &dc,
                             &trav_tmp );
        XNUM_CMP( xml->xrn_dead_code, dc, error );

        if ( error ) {

            error_nlinearity_detected = 1;

        } else {

            X_INV2( xml->xrn_dead_code, dci );
            xrn_vector_traverse( &xml->xvector[i], &xml->xrn_dead_code, &xml->xrn_dead_code, &tmp,
                                 &trav_tmp );
            XNUM_CMP( tmp, dci, error );

            if ( error ) {

                error_nlinearity_detected = 1;

            }

        }

    }

    if ( ( ( error_plain_detected == 1 ) && ( error_permuted_detected == 1 ) )
         || ( error_nlinearity_detected == 1 ) || ( error_running == 1 ) || ( error_ratio == 1 ) ) {

        XPRINT_NOT( 1 );
        return XERR_NOT_MATRIX;

    }

    if ( error_permuted_detected == 0 ) {

        final_ret = xrn_store_warnings_in_return_value( XINFO_PERMUTED_MATRIX, final_ret );

    }

    XPRINT_NOT( 0 );

    return final_ret;
}

void xrn_initialize_genesis_base( xgenesis_base_t * dst
 )
{
    XPRINT_DEB(  );

    for ( int i = 0; i < sizeof( xgenesis_base_t ); i++ ) {
        ( ( uint8_t * ) dst )[i] = 0;
    }

    return;
}

void xrn_initialize_point( xrn_point_t * dst
 )
{
    XPRINT_DEB(  );

    for ( int i = 0; i < sizeof( xrn_point_t ); i++ ) {
        ( ( uint8_t * ) dst )[i] = 0;
    }

    return;
}

void xrn_initialize_base( xrn_base_t * dst
 )
{
    XPRINT_DEB(  );

    for ( int i = 0; i < sizeof( xrn_base_t ); i++ ) {
        ( ( uint8_t * ) dst )[i] = 0;
    }

    return;
}

void xrn_initialize_vector( xrn_vector_t * v
 )
{
    XPRINT_DEB(  );

    for ( int i = 0; i < sizeof( xrn_vector_t ); i++ ) {
        ( ( uint8_t * ) v )[i] = 0;
    }

    return;
}

void xrn_initialize_matrix( xrn_matrix_t * m
 )
{
    XPRINT_DEB(  );

    for ( int i = 0; i < sizeof( xrn_matrix_t ); i++ ) {
        ( ( uint8_t * ) m )[i] = 0;
    }

    return;
}

void xrn_initialize_matrix_compressed( xrn_matrix_compressed_t * m
 )
{
    XPRINT_DEB(  );

    for ( int i = 0; i < sizeof( xrn_matrix_compressed_t ); i++ ) {
        ( ( uint8_t * ) m )[i] = 0;
    }

    return;
}

int xrn_compare_genesis_bases( xgenesis_base_t * obase_0, xgenesis_base_t * obase_1
 )
{
    XPRINT_DEB(  );

    XBIT_TYPE neq;
    int i;

    if ( ( obase_0 == NULL ) || ( obase_1 == NULL ) ) {
        XPRINT_ERR( 2025, XERR_NULL_MSG );
        return XERR_NULL;
    }

    neq = false;                // assuming the two bases are equal

    for ( i = 0; ( i < XNBYTES_ORIGIN ) && ( !neq ); i++ ) {
        // most of the bits
        if ( ( obase_0->base_vector[i] != obase_1->base_vector[i] )
             && ( i != ( ( sizeof( xnum_t ) * 8 ) / 8 ) - 1 ) ) {
            neq = true;
        } else {
            // compering ignoring one bit
            neq = ( obase_0->base_vector[i] & 0xfe ) ^ ( obase_0->base_vector[i] & 0xfe );
        }

    }

    if ( neq ) {
        return XNOT_EQUAL;
    }

    return XEQUAL;

}

int xrn_compare_bases( xrn_base_t * xbase_0, xrn_base_t * xbase_1
 )
{
    XPRINT_DEB(  );

    XBIT_TYPE neq;

    if ( ( xbase_0 == NULL ) || ( xbase_1 == NULL ) ) {
        XPRINT_ERR( 2026, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // assume the two bases are not equal

    XNUM_CMP( xbase_0->sign_vector, xbase_1->sign_vector, neq );

    if ( neq != 1 ) {
        XMAT_CMP( xbase_0->base_matrix, xbase_1->base_matrix, neq );
    }

    if ( neq ) {
        return XNOT_EQUAL;
    } else {
        return XEQUAL;
    }

}

int xrn_compare_vectors( xrn_vector_t * xvector_0, xrn_vector_t * xvector_1
 )
{
    XPRINT_DEB(  );

    XBIT_TYPE neq;

    if ( ( xvector_0 == NULL ) || ( xvector_1 == NULL ) ) {
        XPRINT_ERR( 2027, XERR_NULL_MSG );
        return XERR_NULL;
    }

    neq = xrn_compare_bases( &xvector_0->xbase, &xvector_1->xbase );

    if ( neq != 1 ) {
        XNUM_CMP( xvector_0->entry_point, xvector_1->entry_point, neq );
    }

    if ( neq ) {
        return XNOT_EQUAL;
    }

    return XEQUAL;

}

int xrn_compare_matrices( xrn_matrix_t * xmatrix_0, xrn_matrix_t * xmatrix_1
 )
{
    XPRINT_DEB(  );

    int i;
    XBIT_TYPE neq;

    if ( ( xmatrix_0 == NULL ) || ( xmatrix_1 == NULL ) ) {
        XPRINT_ERR( 2028, XERR_NULL_MSG );
        return XERR_NULL;
    }

    neq = 0;
    for ( i = 0; ( i < ( sizeof( xnum_t ) * 8 ) ) && ( !neq ); i++ ) {
        neq = xrn_compare_vectors( &xmatrix_0->xvector[i], &xmatrix_1->xvector[i] );
    }

    if ( neq != 1 ) {
        XNUM_CMP( xmatrix_0->xrn_dead_code, xmatrix_1->xrn_dead_code, neq );
    }

    if ( neq ) {
        return XNOT_EQUAL;
    }

    return XEQUAL;

}

int xrn_compare_matrices_compressed( xrn_matrix_compressed_t * src0, xrn_matrix_compressed_t * src1
 )
{
    XPRINT_DEB(  );

    XBIT_TYPE neq;

    if ( ( src0 == NULL ) || ( src1 == NULL ) ) {
        XPRINT_ERR( 2029, XERR_NULL_MSG );
        return XERR_NULL;
    }

    XNUM_CMP( src0->change_of_base, src1->change_of_base, neq );
    if ( neq != 1 ) {
        XNUM_CMP( src0->change_of_sign, src1->change_of_sign, neq );
    } else {
        return XNOT_EQUAL;
    }

    if ( neq != 1 ) {
        xrn_compare_genesis_bases( &src0->xgenesis_base, &src1->xgenesis_base );
    } else {
        return XNOT_EQUAL;
    }

    if ( neq ) {
        return XNOT_EQUAL;
    }

    return XEQUAL;

}

int xrn_dump_matrix_compressed( xrn_matrix_compressed_t * xmc, FILE * fp, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint32_t chksum;
    int ret, final_ret;
    xrn_encoding_param_t enc_param;
    uint8_t crc_bytes, state_size;
    xrn_lib_xtype_t type;

    if ( ( xmc == NULL ) || ( fp == NULL ) ) {
        XPRINT_ERR( 2030, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.o_settings ) ) {
        XPRINT_ERR( 665, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    crc_bytes = 1;
    type = c_matrix_compressed;
    state_size = XRN_MIN_ALLOWED_STATE_SIZE;

    ret = xrn_dump_header_file( fp, type, crc_bytes, state_size, &enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2031, XERR_GENERAL_MSG );
        return ret;
    }

    if ( 1 != xrn_fwrite_encoder( xmc, sizeof( xrn_matrix_compressed_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2034, XERR_IO_MSG );
        return XERR_IO;
    }

    chksum = 0xffffffff;
    xrn_crc32( ( uint8_t * ) xmc, sizeof( xrn_matrix_compressed_t ), &chksum );

    if ( 1 != xrn_fwrite_encoder( &chksum, sizeof( uint32_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2035, XERR_IO_MSG );
        return XERR_IO;
    }

    return final_ret;
}

int xrn_dump_genesis_base( xgenesis_base_t * borigin, FILE * fp, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint32_t chksum;
    int ret, final_ret;
    xrn_encoding_param_t enc_param;
    uint8_t crc_bytes, state_size;
    xrn_lib_xtype_t type;

    if ( ( borigin == NULL ) || ( fp == NULL ) ) {
        XPRINT_ERR( 2036, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.o_settings ) ) {
        XPRINT_ERR( 666, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    crc_bytes = 1;
    type = c_genesis;
    state_size = XRN_MIN_ALLOWED_STATE_SIZE;

    ret = xrn_dump_header_file( fp, type, crc_bytes, state_size, &enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 210, XERR_GENERAL_MSG );
        return ret;
    }

    if ( 1 != xrn_fwrite_encoder( borigin, sizeof( xgenesis_base_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2040, XERR_IO_MSG );
        return XERR_IO;
    }

    chksum = 0xffffffff;
    xrn_crc32( ( uint8_t * ) borigin, sizeof( *borigin ), &chksum );

    if ( 1 != xrn_fwrite_encoder( &chksum, sizeof( uint32_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2041, XERR_IO_MSG );
        return XERR_IO;
    }

    return final_ret;
}

int xrn_dump_base( xrn_base_t * src, FILE * fp, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );
    uint32_t chksum;
    int ret, final_ret;
    xrn_encoding_param_t enc_param;
    uint8_t crc_bytes, state_size;
    xrn_lib_xtype_t type;

    if ( ( src == NULL ) || ( fp == NULL ) ) {
        XPRINT_ERR( 2042, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    crc_bytes = 1;
    type = c_base;
    state_size = XRN_MIN_ALLOWED_STATE_SIZE;

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.o_settings ) ) {
        XPRINT_ERR( 668, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    ret = xrn_dump_header_file( fp, type, crc_bytes, state_size, &enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 211, XERR_GENERAL_MSG );
        return ret;
    }

    if ( 1 != xrn_fwrite_encoder( src, sizeof( xrn_base_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2046, XERR_IO_MSG );
        return XERR_IO;
    }

    chksum = 0xffffffff;
    xrn_crc32( ( uint8_t * ) src, sizeof( *src ), &chksum );

    if ( 1 != xrn_fwrite_encoder( &chksum, sizeof( uint32_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2047, XERR_IO_MSG );
        return XERR_IO;
    }

    return final_ret;
}

int xrn_dump_vector( xrn_vector_t * src, FILE * fp, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );
    uint32_t chksum;
    int ret, final_ret;
    xrn_encoding_param_t enc_param;
    uint8_t crc_bytes, state_size;
    xrn_lib_xtype_t type;

    if ( ( src == NULL ) || ( fp == NULL ) ) {
        XPRINT_ERR( 2048, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.o_settings ) ) {
        XPRINT_ERR( 667, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    crc_bytes = 1;
    type = c_vector;
    state_size = XRN_MIN_ALLOWED_STATE_SIZE;

    ret = xrn_dump_header_file( fp, type, crc_bytes, state_size, &enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2032, XERR_GENERAL_MSG );
        return ret;
    }

    if ( 1 != xrn_fwrite_encoder( src, sizeof( xrn_vector_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2052, XERR_IO_MSG );
        return XERR_IO;
    }

    chksum = 0xffffffff;
    xrn_crc32( ( uint8_t * ) src, sizeof( *src ), &chksum );

    if ( 1 != xrn_fwrite_encoder( &chksum, sizeof( uint32_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2053, XERR_IO_MSG );
        return XERR_IO;
    }

    return final_ret;
}

int xrn_dump_matrix( xrn_matrix_t * src, FILE * fp, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint32_t chksum;
    int ret, final_ret;
    xrn_encoding_param_t enc_param;
    uint8_t crc_bytes, state_size;
    xrn_lib_xtype_t type;

    if ( ( src == NULL ) || ( fp == NULL ) ) {
        XPRINT_ERR( 2054, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.o_settings ) ) {
        XPRINT_ERR( 670, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    crc_bytes = 1;
    type = c_matrix;
    state_size = XRN_MIN_ALLOWED_STATE_SIZE;

    ret = xrn_dump_header_file( fp, type, crc_bytes, state_size, &enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 209, XERR_GENERAL_MSG );
        return ret;
    }

    if ( 1 != xrn_fwrite_encoder( src, sizeof( xrn_matrix_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2058, XERR_IO_MSG );
        return XERR_IO;
    }

    chksum = 0xffffffff;
    xrn_crc32( ( uint8_t * ) src, sizeof( *src ), &chksum );

    if ( 1 != xrn_fwrite_encoder( &chksum, sizeof( uint32_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2059, XERR_IO_MSG );
        return XERR_IO;
    }

    return final_ret;
}

int xrn_load_matrix_compressed( FILE * fp, xrn_matrix_compressed_t * xmc, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint32_t chksum_read, chksum;
    int i, ret, final_ret;
    xrn_encoding_param_t enc_param;
    xrn_matrix_compressed_t local;
    uint32_t reserved_0, reserved_1;

    uint8_t crc_bytes, state_size;
    xrn_lib_xtype_t type, exp_type;

    if ( ( xmc == NULL ) || ( fp == NULL ) ) {
        XPRINT_ERR( 2060, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.i_settings ) ) {
        XPRINT_ERR( 672, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    for ( i = 0; i < sizeof( local ); i++ ) {
        ( ( uint8_t * ) & local )[i] = 0;
    }

    final_ret = XSUCCESS;

    exp_type = c_matrix_compressed;
    ret =
        xrn_load_header_file( fp, &crc_bytes, &type, exp_type, &state_size,
                              &reserved_0, &reserved_1, &enc_param, settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2033, XERR_GENERAL_MSG );
        return ret;
    }

    if ( 1 != xrn_fread_decoder( ( uint8_t * ) & local, sizeof( local ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2066, XERR_IO_MSG );
        return XERR_IO;
    }

    chksum = 0xffffffff;
    xrn_crc32( ( uint8_t * ) & local, sizeof( local ), &chksum );

    if ( 1 != xrn_fread_decoder( &chksum_read, sizeof( uint32_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2069, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( chksum != chksum_read ) {
        XPRINT_ERR( 2070, XERR_CRC_MSG );
        return XERR_CRC;
    }

    *xmc = local;

    return final_ret;
}

int xrn_load_genesis_base( FILE * fp, xgenesis_base_t * dst, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint32_t chksum_read, chksum;
    int ret, final_ret;
    xrn_encoding_param_t enc_param;
    xgenesis_base_t local;
    uint8_t crc_bytes, state_size;
    xrn_lib_xtype_t type, exp_type;
    uint32_t reserved_0, reserved_1;

    if ( ( dst == NULL ) || ( fp == NULL ) ) {
        XPRINT_ERR( 2071, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.i_settings ) ) {
        XPRINT_ERR( 673, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    exp_type = c_genesis;
    ret =
        xrn_load_header_file( fp, &crc_bytes, &type, exp_type, &state_size,
                              &reserved_0, &reserved_1, &enc_param, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2037, XERR_GENERAL_MSG );
        return ret;
    }

    if ( 1 != xrn_fread_decoder( ( uint8_t * ) & local, sizeof( local ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2077, XERR_IO_MSG );
        return XERR_IO;
    }

    chksum = 0xffffffff;
    xrn_crc32( ( uint8_t * ) & local, sizeof( local ), &chksum );

    if ( 1 != xrn_fread_decoder( &chksum_read, sizeof( uint32_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2080, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( chksum != chksum_read ) {
        XPRINT_ERR( 2081, XERR_CRC_MSG );
        return XERR_CRC;
    }

    *dst = local;
    return final_ret;
}

int xrn_load_base( FILE * fp, xrn_base_t * dst, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint32_t chksum_read, chksum;
    int ret, final_ret;
    xrn_encoding_param_t enc_param;
    xrn_base_t local;
    uint8_t crc_bytes, state_size;
    xrn_lib_xtype_t type, exp_type;
    uint32_t reserved_0, reserved_1;

    if ( ( dst == NULL ) || ( fp == NULL ) ) {
        XPRINT_ERR( 2082, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.i_settings ) ) {
        XPRINT_ERR( 676, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    exp_type = c_base;
    ret =
        xrn_load_header_file( fp, &crc_bytes, &type, exp_type, &state_size,
                              &reserved_0, &reserved_1, &enc_param, settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2038, XERR_GENERAL_MSG );
        return ret;
    }

    if ( 1 != xrn_fread_decoder( ( uint8_t * ) & local, sizeof( local ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2088, XERR_IO_MSG );
        return XERR_IO;
    }

    chksum = 0xffffffff;
    xrn_crc32( ( uint8_t * ) & local, sizeof( local ), &chksum );

    if ( 1 != xrn_fread_decoder( &chksum_read, sizeof( uint32_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2091, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( chksum != chksum_read ) {
        XPRINT_ERR( 2092, XERR_CRC_MSG );
        return XERR_CRC;
    }

    *dst = local;
    return final_ret;
}

int xrn_load_matrix( FILE * fp, xrn_matrix_t * dst, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    uint32_t chksum_read, chksum;
    int ret, final_ret;
    xrn_encoding_param_t enc_param;
    uint8_t crc_bytes, state_size;
    xrn_lib_xtype_t type, exp_type;
    xrn_matrix_t local;
    uint32_t reserved_0, reserved_1;

    if ( ( dst == NULL ) || ( fp == NULL ) ) {
        XPRINT_ERR( 2093, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.i_settings ) ) {
        XPRINT_ERR( 669, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    exp_type = c_matrix;
    ret =
        xrn_load_header_file( fp, &crc_bytes, &type, exp_type, &state_size,
                              &reserved_0, &reserved_1, &enc_param, settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2039, XERR_GENERAL_MSG );
        return ret;
    }

    if ( 1 != xrn_fread_decoder( ( uint8_t * ) & local, sizeof( local ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2099, XERR_IO_MSG );
        return XERR_IO;
    }

    chksum = 0xffffffff;
    xrn_crc32( ( uint8_t * ) & local, sizeof( local ), &chksum );

    if ( 1 != xrn_fread_decoder( &chksum_read, sizeof( uint32_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2102, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( chksum != chksum_read ) {
        XPRINT_ERR( 2103, XERR_CRC_MSG );
        return XERR_CRC;
    }

    *dst = local;
    return final_ret;
}

int xrn_load_vector( FILE * fp, xrn_vector_t * dst, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );
    uint32_t chksum_read, chksum;
    int ret, final_ret;
    xrn_encoding_param_t enc_param;
    uint8_t crc_bytes, state_size;
    xrn_lib_xtype_t type, exp_type;
    xrn_vector_t local;
    uint32_t reserved_0, reserved_1;

    if ( ( dst == NULL ) || ( fp == NULL ) ) {
        XPRINT_ERR( 2104, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.i_settings ) ) {
        XPRINT_ERR( 671, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    exp_type = c_vector;
    ret =
        xrn_load_header_file( fp, &crc_bytes, &type, exp_type, &state_size,
                              &reserved_0, &reserved_1, &enc_param, settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2043, XERR_GENERAL_MSG );
        return ret;
    }

    if ( 1 != xrn_fread_decoder( ( uint8_t * ) & local, sizeof( local ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2110, XERR_IO_MSG );
        return XERR_IO;
    }

    chksum = 0xffffffff;
    xrn_crc32( ( uint8_t * ) & local, sizeof( local ), &chksum );

    if ( 1 != xrn_fread_decoder( &chksum_read, sizeof( uint32_t ), 1, fp, &enc_param ) ) {
        XPRINT_ERR( 2113, XERR_IO_MSG );
        return XERR_IO;
    }

    if ( chksum != chksum_read ) {
        XPRINT_ERR( 2114, XERR_CRC_MSG );
        return XERR_CRC;
    }

    *dst = local;
    return final_ret;
}

void xrn_doubling( xrn_base_t * src, xrn_base_t * dst
 )
{
    XPRINT_DEB(  );

    int i, j;
    xnum_t row;

    XBIT_TYPE bit_matrix;
    XBIT_TYPE bit_sign;

    xrn_base_t xb_tmp;

    // for every row
    for ( i = 0; i < ( sizeof( xnum_t ) * 8 ); i++ ) {

        xrn_initialize_num( &row );
        bit_sign = BIT_GET( src->sign_vector, i );

        // for every bit in the row
        for ( j = 0; j < ( sizeof( xnum_t ) * 8 ); j++ ) {

            // get every bit in the row
            bit_matrix = BIT_GET( src->base_matrix.xmat[i], j );

            // perform the xor operation
            if ( bit_matrix ) {
                X_XOR2( src->base_matrix.xmat[j], row );
                bit_sign = bit_sign ^ ( BIT_GET( src->sign_vector, j ) );
            }

        }

        // copy in the destination
        xb_tmp.base_matrix.xmat[i] = row;
        BIT_SETVAL( xb_tmp.sign_vector, i, bit_sign );

    }

    *dst = xb_tmp;

    return;
}

void xrn_sum_of_bases( xrn_base_t * src0, xrn_base_t * src1, xrn_base_t * dst
 )
{
    XPRINT_DEB(  );

    int i, j;
    xnum_t row;

    XBIT_TYPE bit_matrix;
    XBIT_TYPE bit_sign;

    xrn_base_t xb_tmp;

    // for every row
    for ( i = 0; i < ( sizeof( xnum_t ) * 8 ); i++ ) {

        xrn_initialize_num( &row );
        bit_sign = BIT_GET( src1->sign_vector, i );

        // for every bit in the row
        for ( j = 0; j < ( sizeof( xnum_t ) * 8 ); j++ ) {

            // get every bit in the row
            bit_matrix = BIT_GET( src1->base_matrix.xmat[i], j );

            // perform the xor operation
            if ( bit_matrix ) {
                X_XOR2( src0->base_matrix.xmat[j], row );
                bit_sign = bit_sign ^ ( BIT_GET( src0->sign_vector, j ) );
            }

        }

        // copy in the destination
        xb_tmp.base_matrix.xmat[i] = row;
        BIT_SETVAL( xb_tmp.sign_vector, i, bit_sign );

    }

    *dst = xb_tmp;

    return;
}

void xrn_dead_code( xrn_base_t * xb, xnum_t * dst
 )
{
    XPRINT_DEB(  );

    xrn_base_t tmp;

    xrn_initialize_base( &tmp );
    xrn_doubling( xb, &tmp );
    xor_of_bases( xb, &tmp, &tmp );
    gaussian_elimination( &tmp );

    for ( int lu = 0; lu < XNBITS_NUM; lu++ )
        dst->xnum[lu] = tmp.sign_vector.xnum[lu];

    return;
}

void xrn_base_number_mul( xrn_base_t * xbase, xnum_t * num, xrn_base_t * dst
 )
{
    XPRINT_DEB(  );

    xnum_t point;
    int i;

    XBIT_TYPE first_one, bit;
    xrn_base_t xb_original, xb_tmp;

    point = *num;

    xb_tmp = *xbase;
    xb_original = *xbase;

    first_one = 0;

    for ( i = ( sizeof( xnum_t ) * 8 ) - 1; i >= 0; i-- ) {

        bit = BIT_GET( point, i );
        // look for the first one starting from the MSB
        if ( bit && ( !first_one ) ) {
            first_one = 1;

            // if the bit is one
        } else if ( bit && first_one ) {

            xrn_doubling( &xb_tmp, &xb_tmp );
            xrn_sum_of_bases( &xb_tmp, &xb_original, &xb_tmp );

            // if the bit is zero
        } else if ( ( !bit ) && first_one ) {

            xrn_doubling( &xb_tmp, &xb_tmp );

        }

    }

    *dst = xb_tmp;

    return;
}

int xrn_vector_traverse( xrn_vector_t * xvl, xnum_t * xrn_dead_code, xnum_t * p, xnum_t * dst,
                         traverse_opt_t * tmp
 )
{
    XPRINT_DEB(  );

    XNUM_CMP( ( *xrn_dead_code ), ( *p ), tmp->b0 );
    XNUM_CMP( xvl->entry_point, ( *p ), tmp->b1 );
    tmp->b1 = ( ( !tmp->b1 ) + ( !tmp->b0 ) ) % 2;

    xrn_initialize_num( &tmp->tmp1 );

    for ( tmp->i = 0; tmp->i < sizeof( xnum_t ) * 8; ( tmp->i )++ ) {

        tmp->bit = 0;
#if ( XNBITS <= 16 ) || ( XUSE_BUILT_IN_INSTRUCTIONS == 0 )

        for ( tmp->j = 0; tmp->j < XNBITS_NUM; ( tmp->j )++ ) {
            tmp->tmp0.xnum[tmp->j] = p->xnum[tmp->j] & xvl->xbase.base_matrix.xmat[tmp->i].xnum[tmp->j];
            tmp->bit = ( tmp->bit ^ ( BIT_GET( tmp->tmp0.xnum[tmp->j], tmp->j ) ) );
        }

#else

        for ( tmp->j = 0; tmp->j < XNBITS_NUM; ( tmp->j )++ ) {
            tmp->tmp0.xnum[tmp->j] = p->xnum[tmp->j] & xvl->xbase.base_matrix.xmat[tmp->i].xnum[tmp->j];
            tmp->bit = tmp->bit ^ PARITY_BIT( tmp->tmp0.xnum[tmp->j] );
        }

#endif

        tmp->bit = ( tmp->bit + tmp->b1 + ( uint16_t ) ( BIT_GET( xvl->xbase.sign_vector, tmp->i ) ) ) % 2;

        if ( tmp->bit ) {
            BIT_SET( ( tmp->tmp1 ), tmp->i );
        }

    }

    *dst = tmp->tmp1;

    return ( int ) ( tmp->b1 );

}

int xrn_matrix_traverse( xrn_matrix_t * xm, xnum_t * p, xnum_t * d, xnum_t * dst,
                         uint8_t * constant_execution, uint8_t * force_linearity, uint8_t * check_sparcity
 )
{
    XPRINT_DEB(  );

    int ret;
    int i;
    xnum_t num1;

    traverse_opt_t tmp;
    int index, tmpi;
    xnum_t d_internal;
    uint8_t vect_perm[XNBITS];
    uint8_t vect[XNBITS];
    uint8_t permutations[XNBITS] = XRN_PERMUTATIONS;

    if ( ( xm == NULL ) || ( p == NULL ) || ( d == NULL ) || ( dst == NULL )
         || ( check_sparcity == NULL ) || ( force_linearity == NULL ) ) {
        XPRINT_ERR( 2115, XERR_NULL_MSG );
        return XERR_NULL;
    }

    if ( ( ( *check_sparcity != 0 ) && ( *check_sparcity != 1 ) ) ||
         ( ( *force_linearity != 0 ) && ( *force_linearity != 1 ) ) ) {
        XPRINT_ERR( 2116, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    num1 = *p;
    d_internal = *d;

    if ( *check_sparcity == 1 ) {

        ret = xrn_check_sparsity( d_internal );
        if ( ret != XSUCCESS ) {
            XPRINT_ERR( 2117, XERR_SPARSE_MKEY_MSG );
            return XERR_SPARSE_MKEY;
        }

    }

    // constant execution
    if ( *constant_execution == 1 ) {

        // correct distance with permutations

        for ( i = 0; i < XNBITS; i++ ) {

            index = permutations[i];
            tmpi = BIT_GET( ( *d ), i );
            BIT_SETVAL( d_internal, index, tmpi );

        }

        // get constant distance

        const_distance_eval( d_internal, vect );

        for ( i = 0; i < XNBITS; i++ ) {

            index = permutations[i];

            vect_perm[i] = vect[index];

        }

        for ( i = 0; i < ( sizeof( xnum_t ) * 8 ); i++ ) {
            if ( vect_perm[i] == 1 ) {
                ret = xrn_vector_traverse( &xm->xvector[i], &xm->xrn_dead_code, &num1, &num1, &tmp );
                if ( ( ret != 0 ) && ( *force_linearity == 1 ) ) {
                    XPRINT_ERR( 2118, XERR_NLINEAR_MSG );
                    return XERR_NLINEAR;
                }

            }

            if ( vect_perm[i] == 2 ) {
                ret = xrn_vector_traverse( &xm->xvector[i], &xm->xrn_dead_code, &num1, &num1, &tmp );
                if ( ( ret != 0 ) && ( *force_linearity == 1 ) ) {
                    XPRINT_ERR( 2119, XERR_NLINEAR_MSG );
                    return XERR_NLINEAR;
                }

                ret = xrn_vector_traverse( &xm->xvector[i], &xm->xrn_dead_code, &num1, &num1, &tmp );
                if ( ( ret != 0 ) && ( *force_linearity == 1 ) ) {
                    XPRINT_ERR( 2120, XERR_NLINEAR_MSG );
                    return XERR_NLINEAR;
                }

            }

        }

        // variable execution

    } else {

        for ( i = 0; i < ( sizeof( xnum_t ) * 8 ); i++ ) {

            index = permutations[i];

            if ( BIT_GET( ( d_internal ), index ) ) {

                ret = xrn_vector_traverse( &xm->xvector[index], &xm->xrn_dead_code, &num1, &num1, &tmp );

                if ( ( ret != 0 ) && ( *force_linearity == 1 ) ) {
                    XPRINT_ERR( 2121, XERR_NLINEAR_MSG );
                    return XERR_NLINEAR;
                }

            }

        }

    }

    *dst = num1;

    return XSUCCESS;

}

void *xrn_matrix_traverse_pthread( void *ptr
 )
{
    XPRINT_DEB(  );

    cmtraverse_t *arg;

    arg = ( cmtraverse_t * ) ptr;
    *arg->linear =
        xrn_matrix_traverse( arg->xm, arg->p, arg->d, arg->dst, arg->constant_execution,
                             arg->force_linearity, arg->check_sparcity );

    return ( void * ) 0;

}

int xrn_permute_matrix( xrn_matrix_t * xm
 )
{
    XPRINT_DEB(  );

    xrn_matrix_t xm_bkp;
    int i, index;
    int permutations[XNBITS] = XRN_PERMUTATIONS;

    if ( xm == NULL ) {
        XPRINT_ERR( 2122, XERR_NULL_MSG );
        return XERR_NULL;
    }

    xm_bkp = *xm;

    for ( i = 0; i < XNBITS; i++ ) {
        index = permutations[i];
        xm->xvector[i] = xm_bkp.xvector[index];
    }

    return XSUCCESS;

}

int xrn_dump_point( xrn_point_t point, FILE * fp, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int ret;
    int final_ret;
    uint8_t crc_bytes, state_size;
    xrn_lib_xtype_t type;

    final_ret = XSUCCESS;

    if ( fp == NULL ) {
        XPRINT_ERR( 2123, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.o_settings ) ) {
        XPRINT_ERR( 677, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    crc_bytes = 1;
    type = c_point;
    state_size = XRN_MIN_ALLOWED_STATE_SIZE;

    ret = dump_xnum( point.point, type, crc_bytes, state_size, fp, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2125, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;
}

int xrn_load_point( xrn_point_t * point, FILE * fp, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int ret;
    int final_ret;
    uint8_t state_size, crc_bytes;
    xrn_lib_xtype_t type, exp_type;

    final_ret = XSUCCESS;

    if ( ( fp == NULL ) || ( point == NULL ) ) {
        XPRINT_ERR( 2126, XERR_NULL_MSG );
        return XERR_NULL;
    }

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.i_settings ) ) {
        XPRINT_ERR( 680, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    exp_type = c_point;
    ret = load_xnum( &point->point, &crc_bytes, &type, exp_type, &state_size, fp, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2128, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;
}

int xrn_make_point_wrapper( FILE * point_fpw, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    xrn_point_t point;
    int final_ret, ret;

    if ( point_fpw == NULL ) {
        XPRINT_ERR( 2129, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // check encoding settings

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.o_settings ) ) {
        XPRINT_ERR( 2130, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    ret = xrn_make_point( &point, settings.rnd_str );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2131, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_dump_point( point, point_fpw, settings );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2132, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;
}

int xrn_make_point( xrn_point_t * point, char rnd_str[XRN_BUFF_SIZE]
 )
{
    XPRINT_DEB(  );

    int final_ret, ret;

    if ( point == NULL ) {
        XPRINT_ERR( 2133, XERR_NULL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    // generate confidential monomial key

    ret = xrn_initialize_true_rnd_num( rnd_str, &point->point );

    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2135, XERR_GENERAL_MSG );
        return ret;
    }

    return final_ret;
}

int xrn_load_header_file( FILE * fpi,
                          uint8_t * crc_bytes,
                          xrn_lib_xtype_t * type,
                          xrn_lib_xtype_t exp_type,
                          uint8_t * state_size,
                          uint32_t * reserved_0,
                          uint32_t * reserved_1,
                          xrn_encoding_param_t * enc_param, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int ret, final_ret, i;
    int nbits;
    uint16_t crc16;
    uint8_t crc_bytes_local;

    xrn_crypto_lib_header_t header_local;

    xrn_crypto_lib_header_t header_local2;

    if ( ( fpi == NULL ) || ( type == NULL ) || ( crc_bytes == NULL ) || ( enc_param == NULL ) ) {
        XPRINT_ERR( 2318, XERR_GENERAL_MSG );
        return XERR_NULL;
    }

    final_ret = XSUCCESS;

    for ( i = 0; i < sizeof( header_local ); i++ ) {
        ( ( uint8_t * ) & header_local )[i] = 0;
    }

    // initialize encoding decoding param

    ret = xrn_check_encoding_settings( settings.encoding_settings.i_settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1979, XERR_GENERAL_MSG );
        return ret;
    }

    // initialize encoding decoding param

    ret = xrn_initialize_encoding_parameters( enc_param, settings.encoding_settings.i_settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 1978, XERR_GENERAL_MSG );
        return ret;
    }

    if ( xrn_fread_decoder( &header_local, sizeof( header_local ), 1, fpi, enc_param ) != 1 ) {
        XPRINT_ERR( 73, XERR_GENERAL_MSG );
        return XERR_IO;
    }

    // checks on header

    header_local2 = header_local;
    header_local2.crc16 = 0xffff;
    crc16 = 0xffff;
    xrn_crc16( ( uint8_t * ) & header_local2, sizeof( header_local2 ) - 1, &crc16 );
    header_local2.crc16 = crc16;

    if ( header_local2.crc16 != header_local.crc16 ) {
        XPRINT_ERR( 135, XERR_CRC_MSG );
        return XERR_CRC;
    }

    ret = xrn_compare_version( header_local.version, header_local.reserved_1 );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2258, XERR_GENERAL_MSG );
        return ret;
    }

    ret = xrn_check_valid_type( ( uint8_t ) ( header_local.type >> 3 ) );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2256, XERR_GENERAL_MSG );
        return ret;
    }

    xrn_load_sub_type( header_local.type, &crc_bytes_local, &nbits );

    if ( header_local.magic_number != XRN_PERMUTATION_NUMBER ) {
        XPRINT_ERR( 40, XERR_MAGIC_MSG );
        return XERR_MAGIC;
    }

    if ( nbits != XNBITS ) {
        XPRINT_ERR( 259, XERR_NBITS_MSG );
        return XERR_NBITS;
    }

    if ( ( ( uint8_t ) ( header_local.type >> 3 ) ) != exp_type ) {
        XPRINT_ERR( 207, XERR_TYPE_MSG );
        return XERR_TYPE;
    }

    if ( ( header_local.state_size < XRN_MIN_ALLOWED_STATE_SIZE )
         && ( header_local.state_size > ( sizeof( xnum_t ) * 8 ) - 1 ) ) {
        XPRINT_ERR( 608, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    if ( crc_bytes_local == 0 ) {
        crc_bytes_local = 1;
    } else if ( crc_bytes_local == 1 ) {
        crc_bytes_local = 2;
    } else if ( crc_bytes_local == 2 ) {
        crc_bytes_local = 4;
    } else if ( crc_bytes_local == 3 ) {
        crc_bytes_local = 8;
    } else {
        XPRINT_ERR( 1073, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    *type = header_local.type >> 3;
    *crc_bytes = crc_bytes_local;
    *state_size = header_local.state_size;
    *reserved_0 = header_local.reserved_0;
    *reserved_1 = header_local.reserved_1;

    return final_ret;

}

int xrn_dump_header_file( FILE * fpo,
                          xrn_lib_xtype_t type,
                          uint8_t crc_bytes,
                          uint8_t state_size,
                          xrn_encoding_param_t * enc_param, xrn_crypto_extra_settings_t settings
 )
{
    XPRINT_DEB(  );

    int ret, i, final_ret;
    xrn_crypto_lib_header_t header;
    uint16_t crc16;

    if ( ( fpo == NULL ) || ( enc_param == NULL ) ) {
        XPRINT_ERR( 2309, XERR_NULL_MSG );
        return XERR_NULL;
    }

    if ( XSUCCESS != xrn_check_encoding_settings( settings.encoding_settings.o_settings ) ) {
        XPRINT_ERR( 681, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    if ( crc_bytes == 1 ) {
        crc_bytes = 0;
    } else if ( crc_bytes == 2 ) {
        crc_bytes = 1;
    } else if ( crc_bytes == 4 ) {
        crc_bytes = 2;
    } else if ( crc_bytes == 8 ) {
        crc_bytes = 3;
    } else {
        XPRINT_ERR( 1049, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    if ( ( state_size < XRN_MIN_ALLOWED_STATE_SIZE )
         && ( state_size > ( sizeof( xnum_t ) * 8 ) - 1 ) ) {
        XPRINT_ERR( 143, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    // initialize encoding decoding param
    ret = xrn_initialize_encoding_parameters( enc_param, settings.encoding_settings.o_settings );
    final_ret = xrn_store_warnings_in_return_value( ret, final_ret );
    if ( final_ret == XERR_GENERAL ) {
        XPRINT_ERR( 2307, XERR_GENERAL_MSG );
        return ret;
    }

    for ( i = 0; i < sizeof( header ); i++ ) {
        ( ( uint8_t * ) & header )[i] = 0;
    }

    if ( XSUCCESS != get_random_bytes( &header.encoding_guard[0], sizeof( header.encoding_guard ) ) ) {
        XPRINT_ERR( 611, XERR_IO_MSG );
        return XERR_IO;
    }

    header.magic_number = XRN_PERMUTATION_NUMBER;

    header.version = XRN_LIB_VERSION;
    header.reserved_0 = settings.component_id;
    header.reserved_1 = XRN_GIT_VERSION;
    xrn_dump_sub_type( &header.type, crc_bytes, XNBITS );
    header.type = ( uint8_t ) ( ( type << 3 ) | header.type );
    header.state_size = state_size;
    header.crc16 = 0xffff;

    crc16 = 0xffff;
    xrn_crc16( ( uint8_t * ) & header, sizeof( header ) - 1, &crc16 );
    header.crc16 = crc16;

    if ( 1 != xrn_fwrite_encoder( &header, sizeof( header ), 1, fpo, enc_param ) ) {
        XPRINT_ERR( 2305, XERR_IO_MSG );
        return XERR_IO;
    }

    return final_ret;

}

int xrn_initialize_header( xrn_lib_xtype_t type,
                           uint8_t crc_bytes,
                           uint8_t state_size, uint32_t component_id, xrn_crypto_lib_header_t * header
 )
{
    XPRINT_DEB(  );

    int i, final_ret;
    xrn_crypto_lib_header_t header_local;
    uint16_t crc16;

    if ( header == NULL ) {
        XPRINT_ERR( 147, XERR_NULL_MSG );
        return XERR_NULL;
    }

    if ( crc_bytes == 1 ) {
        crc_bytes = 0;
    } else if ( crc_bytes == 2 ) {
        crc_bytes = 1;
    } else if ( crc_bytes == 4 ) {
        crc_bytes = 2;
    } else if ( crc_bytes == 8 ) {
        crc_bytes = 3;
    } else {
        XPRINT_ERR( 144, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    if ( ( state_size < XRN_MIN_ALLOWED_STATE_SIZE )
         && ( state_size > ( sizeof( xnum_t ) * 8 ) - 1 ) ) {
        XPRINT_ERR( 145, XERR_SETTINGS_MSG );
        return XERR_SETTINGS;
    }

    final_ret = XSUCCESS;

    for ( i = 0; i < sizeof( header_local ); i++ ) {
        ( ( uint8_t * ) & header_local )[i] = 0;
    }

    if ( XSUCCESS !=
         get_random_bytes( &header_local.encoding_guard[0], sizeof( header_local.encoding_guard ) ) ) {
        XPRINT_ERR( 139, XERR_IO_MSG );
        return XERR_IO;
    }

    header_local.magic_number = XRN_PERMUTATION_NUMBER;

    header_local.version = XRN_LIB_VERSION;
    header_local.reserved_0 = component_id;
    header_local.reserved_1 = XRN_GIT_VERSION;
    xrn_dump_sub_type( &header_local.type, crc_bytes, XNBITS );
    header_local.type = ( uint8_t ) ( ( type << 3 ) | header_local.type );
    header_local.state_size = state_size;
    header_local.crc16 = 0xffff;

    crc16 = 0xffff;
    xrn_crc16( ( uint8_t * ) & header_local, sizeof( header_local ) - 1, &crc16 );
    header_local.crc16 = crc16;

    *header = header_local;

    return final_ret;

}

int xrn_load_default_settings( xrn_crypto_extra_settings_t * settings
 )
{
    XPRINT_DEB(  );

    if ( settings == NULL ) {
        XPRINT_ERR( 1943, XERR_NULL_MSG );
        return XERR_NULL;
    }

    xrn_initialize_encoding_settings( &settings->encoding_settings.i_settings );
    xrn_initialize_encoding_settings( &settings->encoding_settings.o_settings );
    snprintf( settings->rnd_str, XRN_BUFF_SIZE, "%s", "xoronos" );
    settings->crc_bytes = 1;
    settings->state_size = XRN_MIN_ALLOWED_STATE_SIZE;
    settings->thread_enable = 1;
    settings->const_exec_time = 0;
    settings->component_id = XRN_COMPONENT_ID;

    return XSUCCESS;
}

int xrn_get_library_version(
 )
{
    XPRINT_DEB(  );
    return XRN_LIB_VERSION;
}

